iT邦幫忙

2021 iThome 鐵人賽

DAY 23
1
Modern Web

連線網頁卡牌遊戲(Elixir, Phoenix, Liveview)系列 第 23

23 搞半天終於在網頁上啟動遊戲了

  • 分享至 

  • xImage
  •  

發牌員

我們的短期目標是,在網頁上用純文字的方式直接顯示遊戲狀態
並會隨著遊戲更新的時候更新

原本想要把 遊戲 存在房間裡面,但是在這邊已經不需要其他房間的功能了,多一層很煩
我就直接在 ETS 再開另一個表格 叫 games 然後用跟房間一樣的 id 來儲存遊戲狀態

lib/card/application.ex 裡面加在之前的 rooms 表格後面

# 建立 rooms 與 games table 給大家用
:ets.new(:rooms, [:set, :public, :named_table])
:ets.new(:games, [:set, :public, :named_table])

開始寫這一頁的 mount 方法吧
要做的事情有

  1. 從網址撈出id
  2. 請發牌員建立新的遊戲並把 pid 存在 games表格裡面
  3. 用 pid 取得遊戲目前狀態
  4. 顯示在 render

我們先把發牌員做好
新開一個檔案/lib/card/dealer.ex

defmodule Card.Dealer do
  use GenServer

  def init(_) do
    {:ok, []}
  end

  def handle_call(id, _from, games) do
    case :ets.lookup(:games, id) do
      [{^id, pid}] -> {:reply, {id, pid}, games}
      [] ->
        {:ok, pid} = Card.Game.start()
        :ets.insert(:games, {id, pid})
        {:reply, {id, pid}, [id | games]}
    end
  end

  def start_link(_) do
    GenServer.start_link(__MODULE__, [], name: :dealer)
  end

  def maybe_create_game(id) do
    GenServer.call(:dealer, id)
  end
end

每次開始一個新的遊戲,雙方都會想要得到遊戲的 pid
所以統一由一個發牌員來建立,來避免雙方同時各自建立分開的遊戲的情況

再將發牌員放到 lib/card/application.ex 的 start 方法的 children 裡面

  def start(_type, _args) do
    children = [
      # Start the Telemetry supervisor
      CardWeb.Telemetry,
      # Start the PubSub system
      {Phoenix.PubSub, name: Card.PubSub},
      # Start the Endpoint (http/https)
      CardWeb.Endpoint,
      # Start a worker by calling: Card.Worker.start_link(arg)
      # {Card.Worker, arg}
      Card.Dealer # 加在這裡
    ]

    # 建立 rooms 與 games table 給大家用
    :ets.new(:rooms, [:set, :public, :named_table])
    :ets.new(:games, [:set, :public, :named_table])

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Card.Supervisor]
    Supervisor.start_link(children, opts)
  end

ok 之後就回來做 mount 方法

defmodule CardWeb.GameLive.Game do
  use CardWeb, :live_view
  import CardWeb.Component
  alias Card.Game

  def mount(%{"id" => id} = _params, _session, socket) do
    # 請 dealer 給我們一個遊戲
    pid = Card.Dealer.find_or_create_game(id)

    # 用拿到的 pid 跟 查看遊戲狀態
    game = Game.status(pid)
    
    # 把這些資訊存進 assigns 裡面
    {:ok, assign(socket, %{pid: pid, id: id, game: game})}
  end


  # 接著就可以在 畫面上 用 inspect 方法 把原始的資料型態印在網頁上
  def render(assigns) do
    ~H"""
    <div class="flex flex-col items-center h-screen">
      <.logo />
      <%= inspect @game %>
    </div>
    """
  end
end

建立遊戲後,畫面上會有遊戲剛開始的狀態
https://ithelp.ithome.com.tw/upload/images/20211007/20141054qCPaE4divS.png

如果重新整理,可以看到會依照自動出牌的進度,遊戲狀態有改變

但是我們不可能邊玩邊重新整理

明天來用 pubsub 自動更新遊戲狀態


上一篇
22 準備完成後跳轉到遊戲頁面
下一篇
24 讓畫面跟遊戲聯動
系列文
連線網頁卡牌遊戲(Elixir, Phoenix, Liveview)32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言